﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Globalization;

namespace EditAnyString.Extensions
{
	public static class Converter
	{
		public static TypeConverter GetCustomTypeConverter( Type type )
		{
			if( type == typeof( List<int> ) )
				return new GenericListTypeConverter<int>();
			if( type == typeof( List<decimal> ) )
				return new GenericListTypeConverter<decimal>();
			if( type == typeof( List<string> ) )
				return new GenericListTypeConverter<string>();
		
			return TypeDescriptor.GetConverter( type );
		}

		/// <summary>
		/// Converts a value to a destination type.
		/// </summary>
		/// <param name="value">The value to convert.</param>
		/// <param name="destinationType">The type to convert the value to.</param>
		/// <returns>The converted value.</returns>
		public static object To( object value, Type destinationType )
		{
			return To( value, destinationType, CultureInfo.InvariantCulture );
		}

		/// <summary>
		/// Converts a value to a destination type.
		/// </summary>
		/// <param name="value">The value to convert.</param>
		/// <param name="destinationType">The type to convert the value to.</param>
		/// <param name="culture">Culture</param>
		/// <returns>The converted value.</returns>
		public static object To( object value, Type destinationType, CultureInfo culture )
		{
			if( value != null )
			{
				var sourceType = value.GetType();

				TypeConverter destinationConverter = GetCustomTypeConverter( destinationType );
				TypeConverter sourceConverter = GetCustomTypeConverter( sourceType );
				try
				{
					if( destinationConverter != null && destinationConverter.CanConvertFrom( value.GetType() ) )
						return destinationConverter.ConvertFrom( null, culture, value );
					if( sourceConverter != null && sourceConverter.CanConvertTo( destinationType ) )
						return sourceConverter.ConvertTo( null, culture, value, destinationType );
					if( destinationType.IsEnum && value is int )
						return Enum.ToObject( destinationType, (int)value );
					if( !destinationType.IsAssignableFrom( value.GetType() ) )
						return Convert.ChangeType( value, destinationType, culture );
				}
				catch
				{
					return null;
				}
			}
			return value;
		}

		/// <summary>
		/// Converts a value to a destination type.
		/// </summary>
		/// <param name="value">The value to convert.</param>
		/// <typeparam name="T">The type to convert the value to.</typeparam>
		/// <returns>The converted value.</returns>
		public static T To<T>( object value )
		{
			//return (T)Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture);
			return (T)To( value, typeof( T ) );
		}

		/// <summary>
		/// Convert enum for front-end
		/// </summary>
		/// <param name="str">Input string</param>
		/// <returns>Converted string</returns>
		public static string ConvertEnum( string str )
		{
			string result = string.Empty;
			char[] letters = str.ToCharArray();
			foreach( char c in letters )
				if( c.ToString() != c.ToString().ToLower() )
					result += " " + c.ToString();
				else
					result += c.ToString();
			return result;
		}
	}
}
